figma developer

安装量: 68
排名: #11284

安装

npx skills add https://github.com/daffy0208/ai-dev-standards --skill 'Figma Developer'

Figma Developer Turn Figma designs into production-ready code. Core Principle Design is the single source of truth. Designers work in Figma. Developers build from Figma. The bridge between them should be automated, not manual. Phase 1: Setup & Authentication Get Figma Access Token Go to Figma Settings Scroll to "Personal access tokens" Click "Generate new token" Name it (e.g., "Development") Copy and save securely Environment Setup

.env

FIGMA_ACCESS_TOKEN

figd_ .. . Install Figma Client npm install node-fetch Test Connection import { FigmaClient } from '@/integrations/design-tools/figma/client' const client = new FigmaClient ( { accessToken : process . env . FIGMA_ACCESS_TOKEN } ) // Test with a public file const file = await client . getFile ( 'abc123xyz' ) console . log ( 'Connected! File:' , file . name ) Phase 2: Extract Design Tokens What Are Design Tokens? Design tokens are design decisions (colors, typography, spacing) stored as code. Benefits: Single source of truth Consistent across platforms Easy to update Type-safe Extract Tokens from Figma // scripts/sync-design-tokens.ts import { FigmaClient } from '@/integrations/design-tools/figma/client' import fs from 'fs/promises' async function syncDesignTokens ( ) { const client = new FigmaClient ( ) const fileKey = 'YOUR_FIGMA_FILE_KEY' console . log ( 'Extracting design tokens...' ) // Extract tokens const tokens = await client . extractDesignTokens ( fileKey ) console . log ( Found: ) console . log ( ${ tokens . colors . length } colors ) console . log ( ${ tokens . typography . length } text styles ) console . log ( ${ tokens . spacing . length } spacing values ) // Export as CSS const css = await client . exportTokensAsCSS ( fileKey ) await fs . writeFile ( 'src/styles/design-tokens.css' , css ) // Export as JSON const json = await client . exportTokensAsJSON ( fileKey ) await fs . writeFile ( 'src/styles/design-tokens.json' , json ) console . log ( 'Design tokens synced!' ) } syncDesignTokens ( ) Use Tokens in Code // src/styles/design-tokens.css : root { / Colors / -- color - primary :

0066cc

;

color

secondary :

10b981

;

color

neutral

100 :

f9fafb

;

color

neutral

900 :

111827 ; / Typography / -- font - heading - family : Inter ; -- font - heading - size : 48px ; -- font - heading - weight : 700 ; / Spacing / -- space - 4 : 16px ; -- space - 8 : 32px ; } Usage in React: // components/Button.tsx export function Button ( { children } : { children : React . ReactNode } ) { return ( < button style = { { backgroundColor : 'var(--color-primary)' , color : 'white' , padding : 'var(--space-4)' , fontFamily : 'var(--font-heading-family)' , fontWeight : 'var(--font-heading-weight)' , border : 'none' , borderRadius : '8px' , cursor : 'pointer' } }

{ children } </ button

) } Phase 3: Export Assets Export Icons as SVG // scripts/export-icons.ts import { FigmaClient } from '@/integrations/design-tools/figma/client' import fs from 'fs/promises' async function exportIcons ( ) { const client = new FigmaClient ( ) const fileKey = 'YOUR_FIGMA_FILE_KEY' // Get file const file = await client . getFile ( fileKey ) // Find "Icons" frame const iconsFrame = findNode ( file . document , 'Icons' ) if ( ! iconsFrame || ! iconsFrame . children ) { throw new Error ( 'Icons frame not found' ) } console . log ( Found ${ iconsFrame . children . length } icons ) // Export as SVG const iconIds = iconsFrame . children . map ( child => child . id ) const svgs = await client . exportImages ( fileKey , iconIds , { format : 'svg' } ) // Save each SVG for ( const svg of svgs ) { const response = await fetch ( svg . url ) const content = await response . text ( ) await fs . writeFile ( public/icons/ ${ svg . name } .svg , content ) console . log ( ✓ ${ svg . name } .svg ) } console . log ( 'Icons exported!' ) } function findNode ( node : any , name : string ) : any { if ( node . name === name ) return node if ( node . children ) { for ( const child of node . children ) { const found = findNode ( child , name ) if ( found ) return found } } return null } exportIcons ( ) Generate React Icon Components // scripts/generate-icon-components.ts import { FigmaClient } from '@/integrations/design-tools/figma/client' import fs from 'fs/promises' async function generateIconComponents ( ) { const client = new FigmaClient ( ) const fileKey = 'YOUR_FIGMA_FILE_KEY' const file = await client . getFile ( fileKey ) const iconsFrame = findNode ( file . document , 'Icons' ) if ( ! iconsFrame || ! iconsFrame . children ) { throw new Error ( 'Icons frame not found' ) } // Export icons const iconIds = iconsFrame . children . map ( child => child . id ) const svgs = await client . exportImages ( fileKey , iconIds , { format : 'svg' } ) // Generate React components for ( const svg of svgs ) { const response = await fetch ( svg . url ) const svgContent = await response . text ( ) // Convert to React component const componentName = toPascalCase ( svg . name ) const component = import React from 'react' export function ${ componentName } Icon(props: React.SVGProps<SVGSVGElement>) { return ( ${ svgContent . replace ( '<svg' , '<svg {...props}' ) } ) } . trim ( ) await fs . writeFile ( components/icons/ ${ componentName } Icon.tsx , component ) console . log ( ✓ ${ componentName } Icon.tsx ) } // Generate index file const indexContent = svgs . map ( svg => { const componentName = toPascalCase ( svg . name ) return export { ${ componentName } Icon } from './ ${ componentName } Icon' } ) . join ( '\n' ) await fs . writeFile ( 'components/icons/index.ts' , indexContent ) console . log ( 'Icon components generated!' ) } function toPascalCase ( str : string ) : string { return str . split ( / [ -_ \s ] + / ) . map ( word => word . charAt ( 0 ) . toUpperCase ( ) + word . slice ( 1 ) . toLowerCase ( ) ) . join ( '' ) } function findNode ( node : any , name : string ) : any { if ( node . name === name ) return node if ( node . children ) { for ( const child of node . children ) { const found = findNode ( child , name ) if ( found ) return found } } return null } generateIconComponents ( ) Usage: import { HomeIcon , UserIcon , SettingsIcon } from '@/components/icons' export function Navigation ( ) { return ( < nav

< HomeIcon width = { 24 } height = { 24 } /> < UserIcon width = { 24 } height = { 24 } /> < SettingsIcon width = { 24 } height = { 24 } /> </ nav

) } Phase 4: Component Generation Extract Component Structure // scripts/extract-components.ts import { FigmaClient } from '@/integrations/design-tools/figma/client' async function extractComponents ( ) { const client = new FigmaClient ( ) const fileKey = 'YOUR_FIGMA_FILE_KEY' // Get components const components = await client . getFileComponents ( fileKey ) console . log ( 'Components:' ) for ( const [ key , component ] of Object . entries ( components ) ) { console . log ( ${ component . name } ) console . log ( Key: ${ component . key } ) console . log ( Description: ${ component . description } ) } // Get component sets (variants) const componentSets = await client . getComponentSets ( fileKey ) console . log ( '\nComponent Sets:' ) for ( const [ setId , variants ] of Object . entries ( componentSets ) ) { console . log ( Set: ${ setId } ) for ( const variant of variants ) { console . log ( - ${ variant . name } ) } } } extractComponents ( ) Generate Button Component from Figma // scripts/generate-button.ts import { FigmaClient } from '@/integrations/design-tools/figma/client' import fs from 'fs/promises' async function generateButtonComponent ( ) { const client = new FigmaClient ( ) const fileKey = 'YOUR_FIGMA_FILE_KEY' // Get button component const components = await client . getFileComponents ( fileKey ) const buttonComponent = Object . values ( components ) . find ( c => c . name . toLowerCase ( ) . includes ( 'button' ) ) if ( ! buttonComponent ) { throw new Error ( 'Button component not found' ) } // Get component node const file = await client . getFile ( fileKey ) const buttonNode = findNodeById ( file . document , buttonComponent . key ) if ( ! buttonNode ) { throw new Error ( 'Button node not found' ) } // Extract styles const styles = extractStyles ( buttonNode ) // Generate React component const component = ` import React from 'react' interface ButtonProps { variant?: 'primary' | 'secondary' | 'ghost' size?: 'sm' | 'md' | 'lg' children: React.ReactNode onClick?: () => void } export function Button({ variant = 'primary', size = 'md', children, onClick }: ButtonProps) { const baseStyles = { fontFamily: ' ${ styles . fontFamily } ', fontWeight: ${ styles . fontWeight } , fontSize: ' ${ styles . fontSize } px', padding: ' ${ styles . padding } ', borderRadius: ' ${ styles . borderRadius } px', border: 'none', cursor: 'pointer', transition: 'all 0.2s' } const variantStyles = { primary: { backgroundColor: ' ${ styles . backgroundColor } ', color: ' ${ styles . color } ' }, secondary: { backgroundColor: 'transparent', color: ' ${ styles . backgroundColor } ', border: '2px solid ${ styles . backgroundColor } ' }, ghost: { backgroundColor: 'transparent', color: ' ${ styles . color } ' } } return ( <button style={{ ...baseStyles, ...variantStyles[variant] }} onClick={onClick}

{children} ) } . trim ( ) await fs . writeFile ( 'components/Button.tsx' , component ) console . log ( 'Button component generated!' ) } function findNodeById ( node : any , id : string ) : any { if ( node . id === id ) return node if ( node . children ) { for ( const child of node . children ) { const found = findNodeById ( child , id ) if ( found ) return found } } return null } function extractStyles ( node : any ) { return { fontFamily : node . style ?. fontFamily || 'Inter' , fontWeight : node . style ?. fontWeight || 600 , fontSize : node . style ?. fontSize || 16 , padding : '12px 24px' , borderRadius : node . cornerRadius || 8 , backgroundColor : rgbToHex ( node . fills ?. [ 0 ] ?. color || { r : 0 , g : 0.4 , b : 0.8 } ) , color : '#ffffff' } } function rgbToHex ( color : any ) : string { const r = Math . round ( color . r * 255 ) . toString ( 16 ) . padStart ( 2 , '0' ) const g = Math . round ( color . g * 255 ) . toString ( 16 ) . padStart ( 2 , '0' ) const b = Math . round ( color . b * 255 ) . toString ( 16 ) . padStart ( 2 , '0' ) return

${ r } ${ g } ${ b } ` } generateButtonComponent ( ) Phase 5: Automated Workflows Set Up GitHub Actions

.github/workflows/sync-figma.yml

name : Sync Figma Design Tokens on : schedule : - cron : '0 9 * * *'

Every day at 9am

workflow_dispatch :

Manual trigger

jobs : sync : runs-on : ubuntu - latest steps : - uses : actions/checkout@v3 - uses : actions/setup - node@v3 with : node-version : 18 - run : npm install - name : Sync design tokens env : FIGMA_ACCESS_TOKEN : $ { { secrets.FIGMA_ACCESS_TOKEN } } run : npm run sync : design - tokens - name : Create Pull Request uses : peter - evans/create - pull - request@v5 with : title : 'chore: sync design tokens from Figma' body : 'Automated sync of design tokens from Figma' branch : 'figma/sync-tokens' commit-message : 'chore: sync design tokens' Package.json Scripts { "scripts" : { "sync:design-tokens" : "tsx scripts/sync-design-tokens.ts" , "export:icons" : "tsx scripts/export-icons.ts" , "generate:icons" : "tsx scripts/generate-icon-components.ts" , "figma:sync-all" : "npm run sync:design-tokens && npm run generate:icons" } } Best Practices 1. Organize Figma Files Structure: Design System File ├── 📄 Cover (description) ├── 🎨 Colors (all color styles) ├── 📝 Typography (all text styles) ├── 📏 Spacing (spacing guide) ├── 🧩 Components │ ├── Buttons │ ├── Forms │ └── Cards └── 🖼️ Icons (all icons in one frame) 2. Naming Conventions Colors: Primary/500 Secondary/500 Neutral/100 Neutral/900 Success Error Typography: Heading/Large Heading/Medium Body/Regular Body/Small Components: Button/Primary Button/Secondary Card/Default Card/Elevated 3. Use Figma Variables (Beta) Figma now supports variables natively. Use them for: Colors Spacing Border radius Typography sizes Extract these automatically with the API. 4. Version Control // Check for Figma updates async function checkForUpdates ( ) { const client = new FigmaClient ( ) const fileKey = 'YOUR_FIGMA_FILE_KEY' const file = await client . getFile ( fileKey ) const currentVersion = file . version // Store in database or file const previousVersion = await getPreviousVersion ( ) if ( currentVersion !== previousVersion ) { console . log ( 'Figma file updated!' ) console . log ( Version: ${ previousVersion } → ${ currentVersion } ) // Trigger sync await syncDesignTokens ( ) await savePreviousVersion ( currentVersion ) } else { console . log ( 'No updates' ) } } Common Patterns Pattern 1: Token-Based Development // 1. Extract tokens const tokens = await client . extractDesignTokens ( fileKey ) // 2. Generate CSS variables const css = generateCSS ( tokens ) // 3. Generate TypeScript types const types = export type ColorToken = ${ tokens . colors . map ( c => | ' ${ c . name } ' ) . join ( '\n ' ) } export type SpacingToken = ${ tokens . spacing . map ( s => | ' ${ s . name } ' ) . join ( '\n ' ) } . trim ( ) await fs . writeFile ( 'src/types/tokens.ts' , types ) // 4. Use in components import { ColorToken } from '@/types/tokens' interface ButtonProps { color : ColorToken } Pattern 2: Component Sync // Keep components in sync with Figma async function syncComponent ( componentName : string ) { const client = new FigmaClient ( ) const fileKey = 'YOUR_FIGMA_FILE_KEY' // Get component from Figma const components = await client . getFileComponents ( fileKey ) const component = Object . values ( components ) . find ( c => c . name === componentName ) if ( ! component ) { throw new Error ( Component not found: ${ componentName } ) } // Generate code const code = await generateComponentCode ( component ) // Write to file await fs . writeFile ( components/ ${ componentName } .tsx , code ) console . log ( Synced: ${ componentName } ) } Troubleshooting Issue: Token Names Don't Match Problem: Figma style names have spaces/special characters Solution: Normalize names function normalizeTokenName ( name : string ) : string { return name . toLowerCase ( ) . replace ( / [ ^ a - z 0 - 9 ] + / g , '-' ) . replace ( / ^ - | - $ / g , '' ) } Issue: Colors Look Different Problem: RGB values need conversion Solution: Use proper color space conversion function rgbToHex ( color : { r : number ; g : number ; b : number } ) : string { const r = Math . round ( color . r * 255 ) const g = Math . round ( color . g * 255 ) const b = Math . round ( color . b * 255 ) return `

${ r . toString ( 16 ) . padStart ( 2 , '0' ) } ${ g . toString ( 16 ) . padStart ( 2 , '0' ) } ${ b . toString ( 16 ) . padStart ( 2 , '0' ) } ` } Issue: API Rate Limiting Problem: Too many requests Solution: Cache responses const cache = new Map < string , { data : any ; timestamp : number }

( ) async function getCachedFile ( fileKey : string ) { const cached = cache . get ( fileKey ) if ( cached && Date . now ( ) - cached . timestamp < 60000 ) { return cached . data } const file = await client . getFile ( fileKey ) cache . set ( fileKey , { data : file , timestamp : Date . now ( ) } ) return file } Tools & Resources Figma Plugins: Figma Tokens - Manage design tokens Design Tokens - Export tokens Figma to Code - Generate code Libraries: @figma/rest-api-spec - TypeScript types figma-api - Alternative client style-dictionary - Transform tokens

返回排行榜